package com.hmall.item.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.item.dto.ItemDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.item.domain.dto.OrderDetailDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.service.IItemService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author 虎哥
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {

    private final RedisTemplate<String, Object> redisTemplate;

    private final IItemService itemService;

    @Transactional
    @Override
    public void deductStock(List<OrderDetailDTO> items) {
        for (OrderDetailDTO item : items) {
            int i = baseMapper.updateStock(item);
            if (i <= 0) {
                throw new BizIllegalException("库存不足！");
            }
        }
    }

    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
        return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
    }

    @Override
    public void restoreStock(List<OrderDetailDTO> orderDetailDTOS) {
        for (OrderDetailDTO orderDetailDTO : orderDetailDTOS) {
            Item item = getById(orderDetailDTO.getItemId());
            if (item == null) {
                log.warn("商品不存在，ID: {}", orderDetailDTO.getItemId());
                continue;
            }
            item.setStock(item.getStock() + orderDetailDTO.getNum());
            updateById(item);
        }
    }

    @Override
    public List<ItemDTO> queryItemByIdsCache(Collection<Long> ids) {
        //定义空列表
        List<ItemDTO> itemDTOList = new ArrayList<>();
        ids.stream().forEach(id -> {
            //先查询缓存
            Item itemCache = (Item) redisTemplate.opsForValue().get("hmall:item:" + id);
            //如果缓存有则转为ItemDto
            if (Objects.nonNull(itemCache)) {
                ItemDTO itemDTO = BeanUtils.copyBean(itemCache, ItemDTO.class);
                itemDTOList.add(itemDTO);
            } else {
                //查询数据库
                Item itemDB = getById(id);
                if (Objects.nonNull(itemDB)) {
                    //将数据库查询到的数据放入缓存
                    redisTemplate.opsForValue().set("hmall:item:" + id, itemDB);
                    //转为ItemDto
                    ItemDTO itemDTO = BeanUtils.copyBean(itemDB, ItemDTO.class);
                    itemDTOList.add(itemDTO);
                }
            }
        });
        return itemDTOList;
    }

    private final RedissonClient redissonClient;
    @PutMapping
    public void updateItem(@RequestBody ItemDTO item) {

        Long id = item.getId();
        //锁id
        String lockKey = "hmall:item:lock:"+item.getId();
        RLock lock = redissonClient.getLock(lockKey);
        try {
            //尝试获取锁
            boolean b = lock.tryLock(3, 15, TimeUnit.SECONDS);
            if(!b){
                throw new BizIllegalException("操作过于频繁，请稍后再试！");
            }

            try {
                // 不允许修改商品状态，所以强制设置为null，更新时，就会忽略该字段
                item.setStatus(null);
                // 更新
                itemService.updateById(BeanUtils.copyBean(item, Item.class));
                Item item1 = itemService.getBaseMapper().selectById(item.getId());
                item = BeanUtils.copyBean(item1, ItemDTO.class);
                //更新缓存
                redisTemplate.opsForValue().set("hmall:item:"+id,item,1, TimeUnit.HOURS);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }

        }catch (Exception e){
            e.printStackTrace();
        }

    }
}
